<?php
declare (strict_types=1);

namespace app\command;

use app\common\libs\OnlinePay;
use app\common\loader\ModelMerchant;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use yiqiniu\extend\facade\Logger;

/**
 * 支付红包
 */
class CmdPayRedPacket extends Command
{

    protected string $runtime_file = '';

    protected int $timeout = 30;

    private $pendingRedPacketObj = null;
    private $onlinePayObj = null;

    // 没钱的商户
    private array $no_money_mer = [];

    protected function configure()
    {
        // 指令配置
        $this->setName('cmd:payreadpacket')
            ->setDescription('支付红包');

        $this->runtime_file = app()->getRuntimePath() . '.run_pay_red_packet';
    }

    /**
     * @param Input $input
     * @param Output $output
     * @return bool|void
     */
    protected function execute(Input $input, Output $output)
    {
        //
        if (file_exists($this->runtime_file)) {
            $output->writeln('服务正在执行');
            return true;
        }
        file_put_contents($this->runtime_file, '1');
        $output->writeln('开始处理数据');
        // 处理定时任务
        $this->executeAction($input, $output);
        // 指令输出
        unlink($this->runtime_file);
        $output->writeln('服务处理完成');
    }

    /**
     * 执行动作
     * @param Input $input
     * @param Output $output
     * @return void
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    protected function executeAction(Input $input, Output $output): void
    {


        // 1. 获取待指付款的记录
        // 2. 先从商户余额扣除红包金额，扣除成功后，发放红包，扣除失败，增加金额
        // 3. 发放红包
        // 4. 更新付款状态

        $this->pendingRedPacketObj = ModelMerchant::PendingRedPacket();
        $record = $this->pendingRedPacketObj->getPendingRecord();

        $this->onlinePayObj = OnlinePay::getInstance();
        foreach ($record as $row) {
            $msg = '';
            if ($this->processRecord($row, $msg)) {
                $output->info($msg);
            } else {
                $output->error($msg);
            }
        }

    }

    /**
     * @param array $row
     * @param $result_msg
     * @return bool
     */
    private function processRecord(array $row, &$result_msg): bool
    {

        $pendingRedPacketObj = $this->pendingRedPacketObj;
        $onlinePayObj = $this->onlinePayObj;
        //初始化状态
        $status = $pendingRedPacketObj::STATUS_FAIL;
        $order_no = '';
        $msg = '';
        $result = false;
        try {
            $red_packet = (float)$row['red_packet'];
            $re_money = 0;
            // 扣除红包金额
            if (!isset($this->no_money_mer[$row['mer_id']]) && $pendingRedPacketObj->updateMerchantBalance($row['mer_id'], $red_packet, $pendingRedPacketObj::OP_SUB, $re_money)) {
                // 调用企业付款
                $payResult = $onlinePayObj->CompanyPay($row['order_no'], $red_packet, $row['name'], $row['open_id'],$row['vp_title']);

                if ($payResult['result']) {
                    // 支付成功,插入变更日志
                    $status = $pendingRedPacketObj::STATUS_SUCCESS;
                    $order_no = $payResult['data']['order_no'];
                    $pendingRedPacketObj->insertMoneyLog($row['mer_id'], $red_packet, $re_money, $order_no);
                    $result_msg = $row['order_no'] . ' 发放成功';
                } else {
                    // 支付失败，退还余额
                    $msg = $payResult['msg'];
                    $pendingRedPacketObj->updateMerchantBalance($row['mer_id'], $red_packet, $pendingRedPacketObj::OP_ADD, $re_money);
                    $result_msg = $row['order_no'] . ' ' . $msg;
                }

            } else {
                // 保存到数组，下次不再判断
                $this->no_money_mer[$row['mer_id']] = 0;
                $msg = '商户余额不足';
                $result_msg = $row['order_no'] . ' 商户余额不足';
            }
            $result = true;
        } catch (\Exception|\Error $e) {
            Logger::log([
                'code' => $e->getCode(),
                'message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString(),
            ], true, 'cmd_red_packet');
            // 更新付款状态
            $result_msg = $e->getMessage();
        }

        // 更新付款状态
        $pendingRedPacketObj->updatePendingRecord($row['id'], $row['used_log_id'], $status, $msg, $order_no);

        return $result;
    }
}
